//////////
// 逻辑 and/or/not

#include "../basic/operator.h"

Cell* op_and0(Scheme *sc) {
	log(sc, "syntax/logic", "op_and0");
	if (sc->code == G_NIL) {
		sc->returnValue = G_TRUE;
		log(sc, "syntax/logic", "op_and0");
		return pop_callstack(sc);
	}
	push_callstack(sc, cell_op_and1, G_NIL, cdr(sc->code));
	sc->code = car(sc->code);
	sc->op = cell_op_eval;
	log(sc, "syntax/logic", "op_and0");
	return G_TRUE;
}

Cell* op_and1(Scheme *sc) {
	log(sc, "syntax/logic", "op_and1");
	if (is_false(sc->returnValue)) {
		return pop_callstack(sc);
	}
	else if (sc->code == G_NIL) {
		return pop_callstack(sc);
	}
	else {
		push_callstack(sc, cell_op_and1, G_NIL, cdr(sc->code));
		sc->code = car(sc->code);
		sc->op = cell_op_eval;
		log(sc, "syntax/logic", "op_and1");
		return G_TRUE;
	}
}

Cell* op_or0(Scheme *sc) {
	log(sc, "syntax/logic", "op_or0");
	if (sc->code == G_NIL){
		sc->returnValue = G_FALSE;
		log(sc, "syntax/logic", "op_or0");
		return pop_callstack(sc);
	}
	push_callstack(sc, cell_op_or1, G_NIL, cdr(sc->code));
	sc->code = car(sc->code);
	sc->op = cell_op_eval;
	log(sc, "syntax/logic", "op_or0");
	return G_TRUE;
}

Cell* op_or1(Scheme *sc) {
	log(sc, "syntax/logic", "op_or1");
	if (is_true(sc->returnValue)) {
		return pop_callstack(sc);
	}
	else if (sc->code == G_NIL) {
		return pop_callstack(sc);
	}
	else {
		push_callstack(sc, cell_op_or1, G_NIL, cdr(sc->code));
		sc->code = car(sc->code);
		sc->op = cell_op_eval;
		log(sc, "syntax/logic", "op_or1");
		return G_TRUE;
	}
}

// (not x)
Cell* op_not(Scheme *sc) {
	log(sc, "syntax/logic", "op_not");
	int istrue = (is_false(first(sc->args)));
	sc->returnValue = ((istrue) ? G_TRUE : G_FALSE);
	log(sc, "syntax/logic", "op_not");
	return pop_callstack(sc);
}

void init_logic_operators(Scheme *sc) {
	ADD_OPERATOR(sc, "$and0", and0);
	ADD_OPERATOR(sc, "$and1", and1);
	ADD_OPERATOR(sc, "$or0", or0);
	ADD_OPERATOR(sc, "$or1", or1);
	ADD_OPERATOR(sc, "not", not);

	ADD_SYNTAX(sc, "and", and0);
	ADD_SYNTAX(sc, "or", or0);
}
